package com.leador.batch;

import android.content.Context;
import android.util.Log;

import com.leador.assist.DataQueueManager;
import com.leador.batch.db.DatabaseManager;
import com.leador.core.Trace;
import com.leador.db.DBManger;
import com.leador.listener.OnUpCompleteListener;
import com.leador.module.ILocation;
import com.leador.utils.Config;
import com.leador.utils.Utils;

import org.json.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by lhy on 2016/9/25.
 */
public class SyncUpLoadThread extends Thread {
    private Context mcontext;
    private DBManger dbManger;
    private OnUpCompleteListener onUpCompleteListener;
    private List<ILocation> upList = new ArrayList<ILocation>();
    public SyncUpLoadThread(Context mcontext,OnUpCompleteListener onUpCompleteListener){
        this.mcontext = mcontext;
        this.onUpCompleteListener = onUpCompleteListener;
        dbManger = new DBManger();
    }

    @Override
    public void run() {
        super.run();
        onUpCompleteListener.startUp();

        Log.e("traceType",Trace.traceType+"");
        if(Trace.traceType == 2){
            socketUpLoad();
        }

        if(Trace.traceType == 3){
            httpUpLoad();
        }

        onUpCompleteListener.endUp();
    }

    public void socketUpLoad(){
        //Sync 缓存
        Deque bufferDataQueue =  DataQueueManager.getInstance().getBufferDataQueue();
        Deque realtimeDataQueue = DataQueueManager.getInstance().getRealtimeDataQueue();
        Deque tempDataQueue = DataQueueManager.getInstance().getTempDataQueue();

        //Sync 数据库
        dbManger.getSyncData(mcontext);
        Deque dateQueue = DataQueueManager.getInstance().getSyncUpData();

        //all dataqueue
        Deque deque = new LinkedList();
        //temp
        Deque tempDeque = new LinkedList();
        while (bufferDataQueue.size()>0){
            deque.add(bufferDataQueue.poll());
        }
        while (realtimeDataQueue.size()>0){
            deque.add(realtimeDataQueue.poll());
        }
        while (tempDataQueue.size()>0){
            deque.add(tempDataQueue.poll());
        }
        while (dateQueue.size()>0){
            deque.add(dateQueue.poll());
        }

        try{
            Socket s = null;
            String str = null;
            s = new Socket(Config.HOST, Config.PORT);
            s.setSoTimeout(5 * 1000);
            while(deque.size() > 0) {
                    tempDeque.clear();
                    Object object = deque.poll();
                    tempDeque.add(object);
                    List<ILocation> iLocationList = ILocation.jsonToList(new String((byte[])object));
                    if (iLocationList.size() > 0) {
                        for (ILocation iLocation : iLocationList) {
                            String json = actionSocket(ILocation.socketBeanToJson(iLocation), s);
                            JSONObject jsonObject = new JSONObject(json);
                            String status = jsonObject.getString("success");
                            if(!status.equals("0")){
                                //失败入库
                                new DBManger().insert(mcontext,tempDeque);
                            }
                        }
                    }
            }
            if(baos != null){
                baos.close();
            }
            if(s != null){
                s.close();
            }
        }catch (Exception e){
            Log.e("socket 错误",e.getMessage());
            onUpCompleteListener.failure(100,e.getMessage());
            //入库
            dbManger.insert(mcontext,deque);
        }
        finally {
            //TODO 将上报失败的数据再次入库
//            dbManger.insert(mcontext,tempDeque);
        }
    }

    public void httpUpLoad(){
        //Sync 缓存
        try {
            upList.clear();
            Deque deque = DataQueueManager.getInstance().getiLocations();
            if(deque != null && deque.size() > 0){
                while (deque.size()>0){
                    ILocation iLocation = (ILocation) deque.poll();
                    upList.add(iLocation);
                }
            }
        }catch (Exception e){

        }
        try {
            Deque deque = DataQueueManager.getInstance().iLocationTemp;
            if(deque != null && deque.size() > 0){
                while (deque.size()>0){
                    ILocation iLocation = (ILocation) deque.poll();
                    upList.add(iLocation);
                }
            }
        }catch (Exception e){

        }

        //Sync 数据库
        try {
            List<ILocation> iLocationList = DatabaseManager.getInstance(mcontext).getSyncData();
            if(iLocationList!=null&&iLocationList.size()>0){
                upList.addAll(iLocationList);
            }
        }catch (Exception e){

        }

        //ready report
        try{
            //先判断是否有网络
            boolean hsNet = Utils.isNetworkConnected(mcontext);
            if(!hsNet){
                onUpCompleteListener.failure(200,"无网络链接!");
                return;
            }

            if(upList.size()>0){
                Socket s = null;
                for (ILocation iLocation : upList) {
                    s = new Socket(Config.HOST, Config.PORT);
                    s.setSoTimeout(5 * 1000);
                    String json = actionSocket(ILocation.socketBeanToJson(iLocation), s);
                    JSONObject jsonObject = new JSONObject(json);
                    String status = jsonObject.getString("success");
                    if(!status.equals("0")){
                        //失败入库
                        DatabaseManager.getInstance(mcontext).insert(iLocation);
                    }
                }
                if (baos != null) {
                    baos.close();
                }
                if(s != null){
                    s.close();
                }
            }
        }catch (Exception e){
            Log.e("上报失败",e.getMessage());
            String msg = e.getMessage();
            onUpCompleteListener.failure(100,msg);
            //入库
            if(upList.size()>0){
                for(ILocation temILocation : upList){
                    DatabaseManager.getInstance(mcontext).insert(temILocation);
                }
            }
        }

    }

    private byte[] bytes = null;
    private static ByteArrayOutputStream baos = null;
    public static String  actionSocket(String s1, Socket socket) throws Exception {
        byte[] b1 = s1.getBytes();
        byte[] b = intToByteArray1(b1.length);
        byte[] b2 = new byte[b.length + b1.length];
        System.arraycopy(b, 0, b2, 0, b.length);
        System.arraycopy(b1, 0, b2, b.length, b1.length);
        DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
        dos.write(b2);
        dos.flush();
        InputStream in = socket.getInputStream();
        DataInputStream dis = new DataInputStream(in);
        byte[] rheadb = new byte[4];
        dis.read(rheadb);
        int rlen=byteToInt2(rheadb);
        byte[] buffer = new byte[1024];
        baos = new ByteArrayOutputStream();
        for (int i = dis.read(buffer); i > -1; i = dis.read(buffer)) {
            baos.write(buffer, 0, i);
            rlen -= i;
            if (rlen == 0)
                break;
        }
        byte[] result = baos.toByteArray();
        String resultStr = new String(result);
        baos.flush();
        return resultStr;
    }

    public static int byteToInt2(byte[] b) {
        int mask = 0xff;
        int temp = 0;
        int n = 0;
        for (int i = 0; i < 4; i++) {
            n <<= 8;
            temp = b[i] & mask;
            n |= temp;
        }
        return n;
    }

    public static byte[] intToByteArray1(int i) {
        byte[] result = new byte[4];
        result[0] = (byte) ((i >> 24) & 0xFF);
        result[1] = (byte) ((i >> 16) & 0xFF);
        result[2] = (byte) ((i >> 8) & 0xFF);
        result[3] = (byte) (i & 0xFF);
        return result;
    }
}
